home *** CD-ROM | disk | FTP | other *** search
- /* loads3m.c
- *
- * Generic Module Player Screamtracker 3 Module loader
- *
- * $Id: loads3m.c,v 1.15 1997/01/25 15:23:16 pekangas Exp $
- *
- * Copyright 1996,1997 Housemarque Inc.
- *
- * This file is part of the MIDAS Sound System, and may only be
- * used, modified and distributed under the terms of the MIDAS
- * Sound System license, LICENSE.TXT. By continuing to use,
- * modify or distribute this file you indicate that you have
- * read the license and understand and accept it fully.
- */
-
- #include "lang.h"
- #include "mtypes.h"
- #include "errors.h"
- #include "mglobals.h"
- #include "mmem.h"
- #include "file.h"
- #include "sdevice.h"
- #include "gmplayer.h"
- #ifndef NOEMS
- #include "ems.h"
- #endif
- #include "mutils.h"
-
-
- /*#define CHECK_THE_HEAP*/
-
- #ifdef CHECK_THE_HEAP
- #include <malloc.h>
- #endif
-
-
- RCSID(const char *loads3m_rcsid = "$Id: loads3m.c,v 1.15 1997/01/25 15:23:16 pekangas Exp $";)
-
-
-
- /* Pass error code in variable "error" on, used in gmpLoadS3M(). */
- #define PASSERR() { LoadError(); PASSERROR(ID_gmpLoadS3M) }
-
- /****************************************************************************\
- *
- * Function: TestHeap(void)
- *
- * Description: Test if the heap is corrupted. Watcom C ONLY! Implemented here
- * because the Watcom _heapchk() often reports the heap is OK
- * even though it isn't.
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- #if defined(CHECKTHEHEAP) && defined(__WC32__)
- /* Maximum valid block in heap: */
- #define MAXBLK (2048*1024)
-
- int TestHeap(void)
- {
- static struct _heapinfo hinfo;
- int hstatus;
- unsigned len;
-
- hinfo._pentry = NULL;
-
- while ( 1 )
- {
- hstatus = _heapwalk(&hinfo);
- if ( hstatus != _HEAPOK )
- break;
- len = hinfo._size;
- if ( (len == 0) || (len > MAXBLK) || (len & 3) )
- return errHeapCorrupted;
- }
-
- if ( (hstatus == _HEAPEND) || (hstatus == _HEAPEMPTY) )
- return OK;
- return errHeapCorrupted;
- }
-
- #define CHECKHEAP \
- { \
- if ( TestHeap() != OK ) \
- { \
- puts("HEAP CORRUPTED!"); \
- ERROR(errHeapCorrupted, ID_gmpLoadXM); \
- LoadError(); \
- return errHeapCorrupted; \
- } \
- }
- #else
- #define CHECKHEAP
- #endif
-
- /****************************************************************************\
- * struct s3mHeader
- * ----------------
- * Description: Scream Tracker 3 module file header
- \****************************************************************************/
-
- typedef struct
- {
- char name[28]; /* song name */
- U8 num1A; /* 0x1A */
- U8 type; /* file type */
- U16 unused1;
- U16 songLength; /* number of orders */
- U16 numInsts; /* number of instruments */
- U16 numPatts; /* number of patterns */
- U16 flags;
-
- /*
- struct
- {
- int st2Vibrato : 1;
- int st2Tempo : 1;
- int ptSlides : 1;
- int zeroVolOpt : 1;
- int ptLimits : 1;
- int filter : 1;
- int fastVolSlide : 1;
- int unused : 9;
- } flags;
- */
- U16 trackerVer; /* tracker version */
- U16 formatVer; /* file format version */
- char SCRM[4]; /* "SCRM" */
- U8 masterVol; /* master volume */
- U8 speed; /* initial speed */
- U8 tempo; /* initial tempo */
- U8 masterMult; /* master multiplier (bits 0-3),stereo (bit 4) */
- U8 ultraClicks; /* Ultraclick removal info */
- U8 panningMagic; /* 0FCh if panning infos exist */
- U8 unused2[8];
- U16 special; /* pointer to special custom data */
- U8 chanSettings[32]; /* channel settings */
-
- } s3mHeader;
-
-
- /****************************************************************************\
- * struct s3mPattern
- * ----------------
- * Description: Screamtracker 3 Module pattern
- \****************************************************************************/
-
- typedef struct
- {
- U16 pattDataSize; /* pattern data size */
- U8 data[EMPTYARRAY]; /* packed pattern data */
- } s3mPattern;
-
-
- /****************************************************************************\
- * struct s3mInstHdr
- * -----------------
- * Description: Scream Tracker 3 module instrument file header
- \****************************************************************************/
-
- typedef struct
- {
- U8 type; /* instrument type */
- char dosName[12]; /* DOS filename (8+3) */
- char zero; /* 0 */
- U16 samplePtr; /* paragraph ptr to sample data */
- U32 length; /* sample length */
- U32 loopStart; /* sample loop start */
- U32 loopEnd; /* sample loop end */
- U8 volume; /* volume */
- U8 disk; /* instrument disk number */
- U8 pack; /* sample packing info (0 = raw,1 = DP30ADPCM1) */
- U8 flags; /* bit0 = loop, bit1 = stereo,bit2 = 16-bit */
- U32 c2Rate; /* C2 sampling rate */
- U32 unused;
- U16 gusPos; /* position in GUS memory / 32 */
- U16 int512;
- U32 intLastUsed;
- char iname[28]; /* instrument name */
- char SCRS[4]; /* "SCRS" if sample */
- } s3mInstHdr;
-
-
- /* Conversion table from Screamtracker command number to GMP ones: */
- static uchar s3mCommands[26] =
- {
- gmpcSetSpeed, /* A - Set speed */
- gmpcPositionJump, /* B - Position jump */
- gmpcPatternBreak, /* C - Pattern break */
- gmpcVolumeSlide, /* D - Volume slide */
- gmpcSlideDown, /* E - Slide down */
- gmpcSlideUp, /* F - Slide up */
- gmpcTonePortamento, /* G - Tone portamento */
- gmpcVibrato, /* H - Vibrato */
- gmpcNone, /* I - Tremor */
- gmpcArpeggio, /* J - Arpeggio */
- gmpcVibVSlide, /* K - Vibrato + volume slide */
- gmpcTPortVSlide, /* L - Tone portamento + volume slide */
- gmpcNone, /* M - Unused */
- gmpcNone, /* N - Unused */
- gmpcSampleOffset, /* O - Set sample offset */
- gmpcNone, /* P - Unused */
- gmpcS3MRetrig, /* Q - ST3 extended retrig */
- gmpcTremolo, /* R - Tremolo */
- gmpcNone, /* S - S-commands (table below) */
- gmpcSetTempo, /* T - Set tempo */
- gmpcNone, /* U - Fine vibrato */
- gmpcSetMVolume, /* V - Set master volume */
- gmpcMusicSync, /* W - Music synchronization (extension) */
- gmpcSetPanning, /* X - Set panning (extension) */
- gmpcNone, /* Y - Unused */
- gmpcSetPanning16 /* Z - Set panning (extension) */
- };
-
- /* Conversion table from Screamtracker S-command numbers to GMP commands: */
- static uchar s3mSCommands[16] =
- {
- gmpcNone, /* S0 - Set filter */
- gmpcNone, /* S1 - Set glissando control */
- gmpcNone, /* S2 - Set finetune */
- gmpcNone, /* S3 - Set vibrato waveform */
- gmpcNone, /* S4 - Set tremolo waveform */
- gmpcNone, /* S5 - Unused */
- gmpcNone, /* S6 - Unused */
- gmpcNone, /* S7 - Unused */
- gmpcSetPanning16, /* S8 - Set panning */
- gmpcNone, /* S9 - Unused */
- gmpcNone, /* SA - Stereo control (obsolete) */
- gmpcPatternLoop, /* SB - Pattern loop */
- gmpcNoteCut, /* SC - Note cut */
- gmpcNoteDelay, /* SD - Note delay */
- gmpcPatternDelay, /* SE - Pattern delay */
- gmpcNone /* SF - Invert loop (unused in ST3) */
- };
-
-
-
- /****************************************************************************\
- * Module loader buffers and file handle. These variables are static
- * instead of local so that a separate deallocation can be used which
- * will be called before exiting in error situations
- \****************************************************************************/
- static fileHandle f; /* file handle for module file */
- static int fileOpened; /* 1 if module file has been opened */
- static gmpModule *module; /* pointer to GMP module structure */
- static s3mHeader *header; /* pointer to S3M module header */
- static uchar *instUsed; /* instrument used flags */
- static s3mPattern *s3mPatt; /* pointer to S3M pattern data */
- static gmpPattern *convPatt; /* pointer to converted pattern data*/
- static U16 *instPtrs; /* instrument paragraph pointers */
- static U16 *pattPtrs; /* pattern paragraph pointers */
- static uchar *smpBuf; /* sample loading buffer */
- static unsigned numChans; /* number of channels in module */
- static unsigned maxChan; /* maximum enabled channel */
- static unsigned maxInstUsed; /* maximum instrument used */
- static s3mInstHdr s3mi;
-
-
-
-
-
- /****************************************************************************\
- *
- * Function: int ConvertPattern(s3mPattern *srcPatt, gmpPattern *destPatt,
- * unsigned *convLen);
- *
- * Description: Converts a pattern from S3M to GMP internal format.
- * Also updates instUsed flags.
- *
- * Input: s3mPattern *srcPatt pointer to pattern in S3M format
- * gmpPattern *destPatt pointer to destination GMP pattern
- * unsigned *convLen pointer to converted pattern length
- *
- * Returns: MIDAS error code. Converted pattern length (in bytes,
- * including header) is written to *convLen.
- *
- \****************************************************************************/
-
- static int ConvertPattern(s3mPattern *srcPatt, gmpPattern *destPatt,
- unsigned *convLen)
- {
- uchar *src = &srcPatt->data[0];
- uchar *dest = &destPatt->data[0];
- int row;
- unsigned len;
- U8 note, inst, command, infobyte, vol, compInfo;
- U8 s3mComp;
-
- /*
- Packed data consits of following entries:
- BYTE:what 0=end of row
- &31=channel
- &32=follows; BYTE:note, BYTE:instrument
- &64=follows; BYTE:volume
- &128=follows; BYTE:command, BYTE:info
- */
- /* Check if the pattern is empty: */
- if ( (srcPatt->pattDataSize == 0) || (srcPatt == NULL) )
- {
- /* Write row end marker for each row: */
- for ( row = 0; row < 64; row++ )
- *(dest++) = 0;
-
- /* Write number of rows to pattern header: */
- destPatt->rows = 64;
-
- /* Write converted pattern length to header and return it in
- *convLen: */
- *convLen = destPatt->length = 64 + sizeof(gmpPattern);
- return OK;
- }
-
- for ( row = 0; row < 64; row++ )
- {
- while ( *src != 0 )
- {
- /* No data for this channel yet: */
- compInfo = 0;
- note = 0xFF;
- inst = 0xFF;
- command = 0;
- infobyte = 0;
- vol = 0;
-
- /* Get note number/compression info from pattern data: */
- s3mComp = *src++;
-
- /* Check if there is a new note and instrument: */
- if ( s3mComp & 32 )
- {
- /* Check that the note is not key off and convert it to GMP
- internal format: */
- if ( ( *src < 0x7f ) || ( *src == 0xfe ) || ( *src == 0xff ) )
- note = *src;
- src++;
-
- /* Get the instrument number: */
- if ( *src <= module->numInsts )
- inst = (*src) - 1;
-
- src++;
-
- /* Check if the instrument number if above maximum instrument
- number used: */
- if ( inst <= 100 )
- {
- if ( inst < module->numInsts )
- {
- if ( inst > maxInstUsed )
- maxInstUsed = inst;
-
- /* Mark instrument used: */
- instUsed[inst] = 1;
- }
- }
- /* Mark that there is a new note and/or instrument: */
- compInfo |= 32;
-
- if ( numChans <= (unsigned) (s3mComp & 31) )
- numChans = (s3mComp & 31) + 1;
- }
-
- /* Check if there is a volume column byte: */
- if ( s3mComp & 64 )
- {
- /* Get the volume column byte: */
- vol = *(src++);
-
- if ( vol > 63 ) vol = 63;
-
- /* Mark that there is a volume column byte: */
- compInfo |= 64;
- }
-
- /* Check if there is a command: */
- if ( s3mComp & 128 )
- {
- /* Get the command number: */
- command = *(src++);
-
- /* Get the infobyte: */
- infobyte = *(src++);
- }
-
- /* If there is a command or an infobyte we need to write the
- command to the destination pattern: */
- if ( (command > 0) && (command < 26 ) )
- {
- switch ( command )
- {
- case 19:
- /* Command S - check actual command number: */
- command = s3mSCommands[infobyte >> 4];
- infobyte = infobyte & 0x0F;
- break;
-
- default:
- /* Convert command to GMP command number: */
- command = s3mCommands[command - 1];
- break;
- }
-
- /* Mark that there is a command: */
- if ( command != gmpcNone )
- compInfo |= 128;
- }
-
- /* If the compression information is nonzero, there is some
- data for this channel: */
- if ( ( compInfo & 0xE0 ) != 0 )
- {
- /* Set channel number to lower 5 bits of the compression info
- and write it to destination: */
- compInfo |= ( s3mComp & 31 );
- if ( (unsigned) (s3mComp & 31) <= maxChan )
- {
- *(dest++) = compInfo;
-
- /* Check if there a note+instrument pair: */
- if ( compInfo & 32 )
- {
- /* Write note and instrument numbers: */
- *(dest++) = note;
- *(dest++) = inst;
- }
-
- /* Check if there is a volume column byte: */
- if ( compInfo & 64 )
- {
- /* Write the volume column byte: */
- *(dest++) = vol;
- }
-
- /* Check if there is a command: */
- if ( compInfo & 128 )
- {
- /* Write command and command infobyte: */
- *(dest++) = command;
- *(dest++) = infobyte;
- }
- }
- }
- }
-
- /* Write row end marker: */
- *(dest++) = 0;
- src++;
- }
-
- /* Write number of rows to pattern header: */
- destPatt->rows = 64;
-
- /* Calculate converted pattern length: */
- len = (unsigned) (dest - ((uchar*) destPatt));
-
- /* Write converted pattern length to header and return it in *convLen: */
- destPatt->length = len;
- *convLen = len;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: void LoadError(void)
- *
- * Description: Stops loading the module, deallocates all buffers and closes
- * the file.
- *
- \****************************************************************************/
-
- #define condFree(x) { if ( x != NULL ) if ( memFree(x) != OK) return; }
-
- static void LoadError(void)
- {
- /* Close file if opened. Do not process errors. */
- if ( fileOpened )
- if ( fileClose(f) != OK )
- return;
-
- /* Attempt to deallocate module if allocated. Do not process errors. */
- if ( module != NULL )
- if ( gmpFreeModule(module) != OK )
- return;
-
- /* Deallocate structures if allocated: */
- condFree(header)
- condFree(instUsed)
- condFree(smpBuf)
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int gmpLoadS3M(char *fileName, int addSD, mpModule **module)
- *
- * Description: Loads a Scream Tracker 3 module to memory in Generic Module
- * Player module format
- *
- * Input: char *fileName module file name
- * int addSD 1 if module samples should be added to
- * the current Sound Device, 0 if not
- * int (*SampleCallback)(...) pointer to callback function that
- * will be called after sample has been
- * added to Sound Device, but before
- * sample data is deallocated
- * mpModule **module pointer to GMP module pointer
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING gmpLoadS3M(char *fileName, int addSD, int
- (CALLING *SampleCallback)(sdSample *sdsmp, gmpSample *gmpsmp),
- gmpModule **_module)
- {
- int error; /* MIDAS error code */
- gmpInstrument *inst;
- uchar *panningInfos;
- unsigned i;
- ulong maxSample;
- static unsigned convPattLen;
- unsigned slength;
- gmpSample *sample;
- uchar *temp;
- static sdSample sdSmp;
- int n;
- #ifndef NOEMS
- uchar *patt;
- #endif
- int panValue;
- unsigned numS3MPatterns;
- unsigned numUsedPatterns;
-
-
- /* point buffers to NULL and set fileOpened to 0 so that LoadError()
- can be called at any point: */
- fileOpened = 0;
- module = NULL;
- header = NULL;
- instUsed = NULL;
- s3mPatt = NULL;
- convPatt = NULL;
- instPtrs = NULL;
- pattPtrs = NULL;
- smpBuf = NULL;
-
- /* Clear other loader variables: */
- maxInstUsed = 0;
-
- /* Allocate memory for Screamtracker module header: */
- if ( (error = memAlloc(sizeof(s3mHeader), (void**) &header)) != OK )
- PASSERR()
-
- /* Open module file: */
- if ( (error = fileOpen(fileName, fileOpenRead, &f)) != OK )
- PASSERR()
- fileOpened = 1;
-
- /* Allocate memory for the module structure: */
- if ( (error = memAlloc(sizeof(gmpModule), (void**) &module)) != OK )
- PASSERR()
-
- /* Clear module structure so that it can safely be deallocated with
- gmpFreeModule() at any point: */
- module->panning = NULL;
- module->songData = NULL;
- module->instruments = NULL;
- module->patterns = NULL;
-
- /* read Screamtracker module header: */
- if ( (error = fileRead(f, header, sizeof(s3mHeader))) != OK )
- PASSERR()
-
- numChans = 0;
-
- /* Check the module signature: */
- if ( !(mMemEqual(&header->SCRM[0], "SCRM", 4) ) )
- {
- ERROR(errInvalidModule, ID_gmpLoadS3M);
- LoadError();
- return errInvalidModule;
- }
-
-
- /* Copy song name: */
- mMemCopy(&module->name[0], &header->name[0], 28);
- module->name[28] = 0; /* force terminating '\0' */
-
- module->songLength = header->songLength; /* copy song length */
- module->numInsts = header->numInsts; /* set number of instruments */
- numS3MPatterns = header->numPatts; /* store number of patterns */
- module->numPatts = 0; /* not really known yet! */
- module->playMode = gmpST3; /* set ST3 playing mode */
- module->masterVolume = header->masterVol; /* copy master volume */
- module->speed = header->speed; /* initial speed */
- module->tempo = header->tempo; /* initial tempo */
-
- /* Copy some flags */
- module->playFlags.ptLimits = ( header->flags & 0x10 ) >> 4;
- module->playFlags.fastVolSlides = ( header->flags & 0x40 ) >> 6;
- if ( header->trackerVer < 0x1320 )
- module->playFlags.fastVolSlides = 1;
-
- module->restart = 0;
-
- #ifdef DEBUGMESSAGES
- puts("Header ready");
- #endif
- CHECKHEAP
-
- /* Allocate memory for song data: */
- if ( (error = memAlloc(sizeof(ushort) * module->songLength,
- (void**) &module->songData)) != OK )
- PASSERR()
-
- /* read song data: */
- if ( (error = fileRead(f, module->songData, sizeof(uchar) *
- module->songLength)) != OK )
- PASSERR()
-
- /* Calculate real song length: (exclude 0xFF bytes from end) */
- for ( n = (module->songLength - 1); module->songData[n] == 0xFF; n-- );
- module->songLength = n + 1;
-
- /* Convert song data and find the highest pattern number used: */
- temp = (uchar*) module->songData;
- numUsedPatterns = 0;
- for ( n = module->songLength - 1; n >= 0 ; n-- )
- {
- switch ( temp[n] )
- {
- case 0xfe:
- module->songData[n] = 0xfffe;
- break;
-
- case 0xff:
- module->songData[n] = 0xffff;
- break;
-
- default:
- module->songData[n] = temp[n];
- if ( temp[n] >= numUsedPatterns )
- numUsedPatterns = temp[n] + 1;
- }
- }
-
- module->numPatts = numUsedPatterns;
-
- /* check that song length is nonzero: */
- if ( module->songLength == 0 )
- {
- ERROR(errInvalidModule, ID_gmpLoadS3M);
- LoadError();
- return errInvalidModule;
- }
-
- #ifdef DEBUGMESSAGES
- puts("Song data ready");
- printf("Num.patts: %i\n", module->numPatts);
- #endif
- CHECKHEAP
-
- /* Allocate memory for pattern pointers: */
- if ( (error = memAlloc(4 * module->numPatts,
- (void**) &module->patterns)) != OK )
- PASSERR()
-
- /* Set all pattern pointers to NULL to mark them unallocated: */
- for ( i = 0; i < module->numPatts; i++ )
- module->patterns[i] = NULL;
-
- /* Allocate memory for instrument pointers: */
- if ( (error = memAlloc(sizeof(gmpInstrument*) * module->numInsts,
- (void**) &module->instruments)) != OK )
- PASSERR()
-
- /* Set all instrument pointers to NULL to mark them unallocated: */
- for ( i = 0; i < module->numInsts; i++ )
- module->instruments[i] = NULL;
-
- /* Allocate memory for instrument used flags: */
- if ( (error = memAlloc(module->numInsts, (void**)&instUsed)) != OK )
- PASSERR()
-
- /* Mark all instruments unused: */
- for ( i = 0; i < module->numInsts; i++ )
- instUsed[i] = 0;
-
- /* Allocate memory for instrument paragraph pointers: */
- if ( (error = memAlloc(sizeof(U16) * module->numInsts, (void**)
- &instPtrs)) != OK )
- PASSERR()
-
- /* Read instrument pointers: */
- if ( (error = fileRead(f, instPtrs, sizeof(U16) * module->numInsts))
- != OK )
- PASSERR()
-
- /* Allocate memory for S3M file pattern pointers: */
- if ( (error = memAlloc(sizeof(U16) * numS3MPatterns, (void**)
- &pattPtrs)) != OK )
- PASSERR()
-
- /* Read pattern pointers: */
- if ( (error = fileRead(f, pattPtrs, sizeof(U16) * numS3MPatterns))
- != OK )
- PASSERR()
-
- #ifdef DEBUGMESSAGES
- puts("Misc. pointers ready");
- #endif
- CHECKHEAP
-
- /* Allocate memory for channel initial panning positions: */
- if ( (error = memAlloc(32 * sizeof(int), (void**) &module->panning))
- != OK )
- PASSERR()
-
- if ( header->panningMagic == 0xFC )
- {
- /* Allocate memory for panning infos: */
- if ( (error = memAlloc(32 * sizeof(uchar),
- (void**) &panningInfos)) != OK )
- PASSERR()
-
- /* Read panning infos: */
- if ( ( error = fileRead(f, panningInfos, 32 * sizeof(uchar)) ) != OK )
- PASSERR()
-
- /* Convert panning values: */
- for (i = 0; i < 32; i++)
- {
- if ( header->chanSettings[i] > 15 )
- {
- module->panning[i] = 0x40;
- }
- else
- {
- maxChan = i;
- if ( panningInfos[i] & 0x20 )
- {
- panValue = panningInfos[i] & 0xF;
- if ( panValue < 7 )
- {
- module->panning[i] = 8 * panValue;
- }
- else
- {
- if ( panValue > 8 )
- module->panning[i] = 0x80 - (15 - panValue) * 8;
- else
- module->panning[i] = 0x40;
- }
- }
- else
- {
- if (header->chanSettings[i] < 8)
- module->panning[i] = 0x00;
- else
- module->panning[i] = 0x80;
- }
- }
- }
-
- /* Free panning infos: */
- if ( (error = memFree(panningInfos)) != OK )
- PASSERR()
- panningInfos = NULL;
- }
- else
- {
- /* copy default channel panning settings: */
- for (i = 0; i < 32; i++)
- {
- if (header->chanSettings[i] > 15)
- module->panning[i] = 0;
- else
- {
- maxChan = i;
- if (header->chanSettings[i] < 8)
- module->panning[i] = 0x00;
- else
- module->panning[i] = 0x80;
- }
- }
- }
-
- #ifdef DEBUGMESSAGES
- puts("Panning ready");
- #endif
- CHECKHEAP
-
- /* Find maximum sample length: */
- maxSample = 0;
- for ( i = 0; i < module->numInsts; i++ )
- {
- /* Seek to instrument header in file: */
- if ( (error = fileSeek(f, 16L * instPtrs[i], fileSeekAbsolute))
- != OK )
- PASSERR()
-
- /* Read instrument header from file: */
- if ( (error = fileRead(f, &s3mi, sizeof(s3mInstHdr))) != OK )
- PASSERR()
-
- if ( maxSample < s3mi.length )
- maxSample = s3mi.length;
- }
-
- /* Check that the maximum sample length is below the Sound Device limit:*/
- if ( maxSample > SMPMAX )
- {
- ERROR(errInvalidInst, ID_gmpLoadS3M);
- LoadError();
- return errInvalidInst;
- }
-
- #ifdef DEBUGMESSAGES
- puts("Max. sample ready");
- printf("Max. sample: %i\n", maxSample);
- #endif
- CHECKHEAP
-
- /* Allocate memory for pattern loading buffer: */
- if ( (error = memAlloc(32 * 64 * 6 + sizeof(s3mPattern),
- (void**) &s3mPatt)) != OK )
- PASSERR()
-
- /* Allocate memory for pattern conversion buffer: (maximum GMP pattern
- data size is 6 bytes per row per channel plus header) */
- if ( (error = memAlloc(32 * 64 * 6 + sizeof(gmpPattern),
- (void**) &convPatt)) != OK )
- PASSERR()
-
- #ifdef DEBUGMESSAGES
- puts("Ready for conversion");
- #endif
- CHECKHEAP
-
- /* Load and convert all patterns: */
- for ( i = 0; i < module->numPatts; i++ )
- {
- if ( (i < numS3MPatterns) && (pattPtrs[i] != 0) )
- {
- #ifdef DEBUGMESSAGES
- puts("Seek");
- #endif
- CHECKHEAP
- /* Seek to pattern beginning in file: */
- if ( (error = fileSeek(f, 16L * pattPtrs[i], fileSeekAbsolute))
- != OK )
- PASSERR()
-
- #ifdef DEBUGMESSAGES
- puts("Read pattern length");
- #endif
- CHECKHEAP
- /* Read pattern length from file: */
- if ( (error = fileRead(f, &s3mPatt->pattDataSize, sizeof(U16))) != OK )
- PASSERR()
-
- #ifdef DEBUGMESSAGES
- printf("Patt.len: %i\n", s3mPatt->pattDataSize);
- puts("Read pattern data");
- #endif
- CHECKHEAP
- /* Read pattern data from file: */
- if ( (error = fileRead(f, &s3mPatt->data[0], s3mPatt->pattDataSize)) != OK )
- PASSERR()
- }
- else
- {
- s3mPatt->pattDataSize = 0;
- #ifdef DEBUGMESSAGES
- puts("Empty pattern");
- #endif
- }
- #ifdef DEBUGMESSAGES
- puts("Convert pattern");
- #endif
- CHECKHEAP
-
- /* Convert the pattern data, checking the instruments used: */
- if ( (error = ConvertPattern(s3mPatt, convPatt, &convPattLen))
- != OK )
- PASSERR()
-
- #if 0
- #ifndef NOEMS
- if ( mUseEMS == 1 ) /* is EMS memory used? */
- {
- /* Allocate EMS for converted pattern data for current pattern in
- module: */
- if ( (error = emsAlloc(convPattLen, (emsBlock**)
- &module->patterns[i])) != OK )
- PASSERR()
-
- /* Map the allocated EMS block to conventional memory: */
- if ( (error = emsMap((emsBlock*) module->patterns[i],
- (void**) &patt)) != OK)
- PASSERR()
-
- /* Copy the converted pattern data to the EMS block: */
- mMemCopy(patt, convPatt, convPattLen);
- }
- else
- #endif
-
- #endif
- {
- #ifdef DEBUGMESSAGES
- printf("Alloc mem: %i\n", convPattLen);
- #endif
- CHECKHEAP
- /* Allocate memory for converted pattern data for current pattern
- in module: */
- if ( (error = memAlloc(convPattLen, (void**)&module->patterns[i]))
- != OK )
- PASSERR()
-
-
- #ifdef DEBUGMESSAGES
- puts("Copy pattern");
- #endif
- CHECKHEAP
- /* Copy the converted pattern data: */
- mMemCopy(module->patterns[i], convPatt, convPattLen);
- }
- #ifdef DEBUGMESSAGES
- printf("Pattern %i, Conv.len: %i\n", i, convPattLen);
- #endif
- CHECKHEAP
- }
-
- maxChan++;
- /* store number of channels */
- module->numChannels = ( maxChan < numChans ) ? maxChan : numChans;
- #ifdef DEBUGMESSAGES
- printf("Num.channels: %i\n", module->numChannels);
- #endif
- CHECKHEAP
-
- /* Deallocate pattern paragraph pointers: */
- if ( (error = memFree(pattPtrs)) != OK )
- PASSERR()
- pattPtrs = NULL;
-
- /* Deallocate pattern conversion buffer: */
- if ( (error = memFree(convPatt)) != OK )
- PASSERR()
- convPatt = NULL;
-
- /* Deallocate pattern loading buffer: */
- if ( (error = memFree(s3mPatt)) != OK )
- PASSERR()
- s3mPatt = NULL;
-
- #ifdef DEBUGMESSAGES
- puts("Pattern conversion ready");
- #endif
- CHECKHEAP
-
- /* If samples should be added to Sound Device, allocate memory for sample
- loading buffer: */
- if ( addSD )
- {
- if ( (error = memAlloc(maxSample, (void**) &smpBuf)) != OK )
- PASSERR()
- }
-
- if ( maxInstUsed > module->numInsts )
- module->numInsts = maxInstUsed;
-
- #ifdef DEBUGMESSAGES
- printf("Max.inst. used: %i\n", maxInstUsed);
- #endif
- CHECKHEAP
-
- /* Load all samples and convert sample and instrument data: */
- for ( i = 0; i < module->numInsts; i++ )
- {
- /* Seek to instrument header in file: */
- if ( (error = fileSeek(f, 16L * instPtrs[i], fileSeekAbsolute))
- != OK )
- PASSERR()
-
- /* Read instrument header from file: */
- if ( (error = fileRead(f, &s3mi, sizeof(s3mInstHdr))) != OK )
- PASSERR()
-
- /* Allocate memory for this instrument structure: (add space for one
- sample if the instrument is used) */
- if ( instUsed[i] )
- {
- if ( (error = memAlloc(sizeof(gmpInstrument) + sizeof(gmpSample),
- (void**) &module->instruments[i])) != OK )
- PASSERR()
- }
- else
- {
- if ( (error = memAlloc(sizeof(gmpInstrument),
- (void**) &module->instruments[i])) != OK )
- PASSERR()
- }
-
- /* Point inst to current instrument structure: */
- inst = module->instruments[i];
-
- /* Mark there are no sample for the instrument: */
- inst->numSamples = 0;
-
- /* Copy instrument name: */
- mMemCopy(&inst->name[0], &s3mi.iname[0], 28);
- inst->name[28] = 0; /* force terminating '\0' */
-
- /* Mark the instrument has no sample number table for keyboard
- notes: */
- inst->noteSamples = NULL;
-
- /* Mark the instrument has no volume or panning envelopes: */
- inst->volEnvelope = NULL;
- inst->panEnvelope = NULL;
-
- /* Mark the instrument has no FT2 auto-vibrato: */
- inst->vibType = inst->vibSweep = inst->vibDepth = inst->vibRate = 0;
-
- /* Check if the instrument is used in the module: */
- if ( instUsed[i] )
- {
- /* The instrument is used - mark it used and point sample to its
- sample information: */
- inst->used = 1;
- inst->numSamples = 1;
- sample = &inst->samples[0];
-
- /* Mark there is no sample data and the sample has not been added
- to Sound Device: */
- sample->sample = NULL;
- sample->sdHandle = 0;
-
- /* Copy sample loop start and calculate loop end: */
- sample->loop1Start = s3mi.loopStart;
- sample->loop1End = s3mi.loopEnd;
-
- slength = s3mi.length;
-
- if ( ( s3mi.flags & 1 ) && ( s3mi.loopStart != s3mi.loopEnd ) )
- {
- /* Looping sample - set loop types and limit sample length
- to loop end: */
- sample->loopMode = sdLoop1;
- sample->loop1Type = loopUnidir;
- if ( slength > sample->loop1End )
- slength = sample->loop1End;
- }
- else
- {
- /* Sample not looping: */
- sample->loopMode = sdLoopNone;
- sample->loop1Type = loopNone;
- }
-
- /* Set sample length: */
- sample->sampleLength = slength;
-
- /* Copy sample default volume: */
- sample->volume = s3mi.volume;
-
- /* No finetune used: */
- sample->finetune = 0;
-
- /* Copy sample base tune: */
- sample->baseTune = s3mi.c2Rate;
-
- /* Set sample default panning position to middle: */
- sample->panning = panMiddle;
-
- /* Check if there is sample data for this sample: */
- if ( slength != 0 )
- {
- /* If sample data should not be added to Sound Device, allocate
- memory for the sample data and point smpBuf there: */
- if ( !addSD )
- {
- smpBuf = NULL;
- if ( (error = memAlloc(slength, (void**)&smpBuf)) != OK )
- PASSERR()
- sample->sample = smpBuf;
- }
- else
- {
- /* Sample is added to the Sound Device - sample data is not
- available: */
- sample->sample = NULL;
- }
-
- /* Seek to instrument in file: */
- if ( (error = fileSeek(f, 16L * s3mi.samplePtr, fileSeekAbsolute))
- != OK )
- PASSERR()
-
- /* There is sample data - load sample: */
- if ( (error = fileRead(f, smpBuf, slength)) != OK )
- PASSERR()
-
- /* Set Sound Device sample type: */
- sdSmp.sampleType = smp8bit;
- sample->sampleType = smp8bit;
-
- /* Set Sound Device sample position in memory: */
- sdSmp.samplePos = sdSmpConv;
-
- /* Point Sound Device sample data to sample loading buffer: */
- sdSmp.sample = smpBuf;
-
- /* Point smpBuf to NULL if the sample is not added to Sound
- Device to mark it should not be deallocated: */
- if ( !addSD )
- smpBuf = NULL;
- }
- else
- {
- /* Mark there is no sample data: */
- sdSmp.sampleType = smpNone;
- sdSmp.samplePos = sdSmpNone;
- sdSmp.sample = NULL;
- }
-
- sdSmp.sampleLength = slength;
- sdSmp.loopMode = sample->loopMode;
- sdSmp.loop1Start = sample->loop1Start;
- sdSmp.loop1End = sample->loop1End;
- sdSmp.loop1Type = sample->loop1Type;
-
-
- /* Set up the rest of Sound Device sample structure so that the sample
- can be added to the Sound Device: */
- if ( addSD )
- {
-
- /* Add the sample to Sound Device and store the Sound Device
- sample handle in sample->sdHandle: */
- if ( (error = gmpSD->AddSample(&sdSmp, 1, &sample->sdHandle))
- != OK)
- PASSERR()
-
- /* Call sample callback if used: */
- if ( SampleCallback != NULL )
- {
- if ( (error = SampleCallback(&sdSmp, sample)) != OK )
- PASSERR()
- }
- }
- else
- {
- /* Sample data has not been added to Sound Device: */
- sample->sdHandle = 0;
- }
- }
- else
- {
- /* Sample is not used - there is no sample data: */
- inst->used = 0;
- inst->numSamples = 0;
- }
-
- #ifdef DEBUGMESSAGES
- printf("Inst: %i, Len: %i\n", i, slength);
- #endif
- CHECKHEAP
- }
-
- /* Deallocate sample loading buffer if allocated: */
- if ( addSD )
- {
- if ( (error = memFree(smpBuf)) != OK )
- PASSERR()
- }
- smpBuf = NULL;
-
- /* Deallocate instrument paragraph pointers: */
- if ( (error = memFree(instPtrs)) != OK )
- PASSERR()
- instPtrs = NULL;
-
- /* Deallocate instrument use flags: */
- if ( (error = memFree(instUsed)) != OK )
- PASSERR()
- instUsed = NULL;
-
- #ifdef DEBUGMESSAGES
- puts("Samples ready");
- #endif
- CHECKHEAP
-
- /* Now we are finished loading. Close module file: */
- if ( (error = fileClose(f)) != OK)
- PASSERR()
- fileOpened = 0;
-
- /* Deallocate Screamtracker module header: */
- if ( (error = memFree(header)) != OK )
- PASSERR();
-
- /* Return module pointer in *module: */
- *_module = module;
-
- #ifdef DEBUGMESSAGES
- puts("Load Ok");
- #endif
- CHECKHEAP
-
- return OK;
- }
-
-
- /*
- * $Log: loads3m.c,v $
- * Revision 1.15 1997/01/25 15:23:16 pekangas
- * The file is now closed properly if loading terminates to an error
- *
- * Revision 1.14 1997/01/16 18:41:59 pekangas
- * Changed copyright messages to Housemarque
- *
- * Revision 1.13 1996/12/30 23:38:08 jpaana
- * Cleaned up LoadError
- *
- * Revision 1.12 1996/09/08 21:00:42 pekangas
- * Fixed Set Tempo -command
- *
- * Revision 1.11 1996/09/05 06:28:28 pekangas
- * Changed S8 command to SetPanning16 (was SetPanning) (thanks Zapper)
- *
- * Revision 1.10 1996/09/01 15:42:31 pekangas
- * Changed to use new style slides (no more signed infobytes)
- *
- * Revision 1.9 1996/08/06 19:18:48 pekangas
- * Fixed to produce legal gmpModules so that mod2gm works
- *
- * Revision 1.8 1996/08/02 19:46:10 pekangas
- * Kluged to skip all instruments above module->numInsts to prevent crashes
- *
- * Revision 1.7 1996/07/16 17:35:35 pekangas
- * Fixed song data conversion loop
- *
- * Revision 1.6 1996/07/13 20:19:32 pekangas
- * Eliminated Visual C warnings
- *
- * Revision 1.5 1996/07/13 18:30:19 pekangas
- * Fixed to compile with Visual C
- *
- * Revision 1.4 1996/06/14 16:23:28 pekangas
- * Removed heap checking to speed up loading
- *
- * Revision 1.3 1996/05/24 17:03:24 pekangas
- * Fixed to work with Watcom C again - using EMPTYARRAY
- *
- * Revision 1.2 1996/05/24 16:20:36 jpaana
- * Fixed to work with gcc
- *
- * Revision 1.1 1996/05/22 20:49:33 pekangas
- * Initial revision
- *
- */
-